﻿//===================================================================================
// Copyright (c) Ryan Garrett.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===================================================================================

using Caffeine.Core.Test.TestModel;
using Caffeine.Core.Test.TestModel;
using Caffeine.Core.Test.TestModel.PropertyRegistrations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace Caffeine.Core.Test
{
    [TestClass]
    public class ModelPropertyTester
    {
        [TestMethod]
        public void ValidationMethodTest()
        {
            ModelForValidationTesting viewModel = Creator.Create<ModelForValidationTesting>();
            List<String> propertyChangeNotifications = new List<String>();

            viewModel.Property.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
            {
                propertyChangeNotifications.Add(e.PropertyName);
            };

            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 0);
            Assert.IsFalse(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = null;
                isValid = true;
            };

            viewModel.Property.Validate();

            Assert.IsFalse(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);
            Assert.AreEqual(propertyChangeNotifications.Count, 0);

            ValidationError errorA = new ValidationError()
            {
                ErrorCode = 1,
                ErrorDescription = "Error 1"
            };

            ValidationError errorADuplicate = new ValidationError()
            {
                ErrorCode = 1,
                ErrorDescription = "Error 1"
            };

            ValidationError errorB = new ValidationError()
            {
                ErrorCode = 2,
                ErrorDescription = "Error 2"
            };

            List<ValidationError> errorCollectionA = new List<ValidationError>();
            errorCollectionA.Add(errorA);
            errorCollectionA.Add(errorB);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionA;
                isValid = true;
            };

            viewModel.Property.Validate();

            Assert.IsFalse(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);
            Assert.AreEqual(propertyChangeNotifications.Count, 0);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionA;
                isValid = false;
            };

            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 2);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.AreEqual(propertyChangeNotifications[1], "IsInvalid");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionA);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionA;
                isValid = true;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 2);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.AreEqual(propertyChangeNotifications[1], "IsInvalid");
            Assert.IsFalse(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = null;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "IsInvalid");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionA;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionA);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionA;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 0);
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionA);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = null;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = null;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 0);
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = null;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 0);
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionA;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionA);

            List<ValidationError> errorCollectionB = new List<ValidationError>();
            errorCollectionB.Add(errorADuplicate);
            errorCollectionB.Add(errorB);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionB;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 0);
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionA);

            errorCollectionB.Add(errorA);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionB;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionB);

            errorCollectionA.Clear();
            errorCollectionA.AddRange(errorCollectionB);
            ValidationError tempError = errorCollectionA[1];
            errorCollectionA[1] = errorCollectionA[2];
            errorCollectionA[2] = tempError;

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionA;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionA);

            errorCollectionB.Clear();
            errorCollectionB.AddRange(errorCollectionA);
            errorCollectionB[1] = null;

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionB;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionB);

            errorCollectionA[1] = null;

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionA;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 0);
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionB);

            errorCollectionA[1] = errorB;

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionA;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionA);

            errorCollectionB.Clear();

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionB;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionB);

            errorCollectionA.Clear();

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionA;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 0);
            Assert.IsTrue(viewModel.Property.IsInvalid);

            //REMEMBER: If the collections contain the same contents (which in this case they do), the collection is not swapped out.
            Assert.AreEqual(viewModel.Property.ValidationErrors, errorCollectionB);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = errorCollectionB;
                isValid = true;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 2);
            Assert.AreEqual(propertyChangeNotifications[0], "ValidationErrors");
            Assert.AreEqual(propertyChangeNotifications[1], "IsInvalid");
            Assert.IsFalse(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);

            viewModel.Property.ValidationMethod = delegate(ModelProperty<String> property, ref IEnumerable<ValidationError> validationErrors, ref Boolean isValid)
            {
                validationErrors = null;
                isValid = false;
            };

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "IsInvalid");
            Assert.IsTrue(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);

            viewModel.Property.ValidationMethod = null;

            propertyChangeNotifications.Clear();
            viewModel.Property.Validate();

            Assert.AreEqual(propertyChangeNotifications.Count, 1);
            Assert.AreEqual(propertyChangeNotifications[0], "IsInvalid");
            Assert.IsFalse(viewModel.Property.IsInvalid);
            Assert.IsNull(viewModel.Property.ValidationErrors);
        }

        [TestMethod]
        public void ValidationMethodChainTest()
        {
            ModelForValidationTesting viewModel = Creator.Create<ModelForValidationTesting>();
            Int32 validationMethod1Called = 0;
            Int32 validationMethod2Called = 0;
            Int32 validationMethod3Called = 0;
            List<string> validationCalls = new List<string>();

            viewModel.Property.ChainValidationMethod(null);
            Assert.IsNull(viewModel.Property.ValidationMethod);

            viewModel.Property.ChainValidationMethod(null);
            Assert.IsNull(viewModel.Property.ValidationMethod);

            viewModel.Property.ChainValidationMethod
            (
                (
                    ModelProperty<string> property,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = true; validationMethod1Called++; validationCalls.Add("Method1"); }
            );
            Assert.IsNotNull(viewModel.Property.ValidationMethod);
            viewModel.Property.Validate();

            Assert.AreEqual(validationMethod1Called, 1);
            Assert.AreEqual(validationCalls.Count, 1);
            Assert.AreEqual(validationCalls[0], "Method1");

            validationMethod1Called = 0;
            validationCalls.Clear();

            viewModel.Property.ChainValidationMethod(null);
            Assert.IsNotNull(viewModel.Property.ValidationMethod);
            viewModel.Property.Validate();

            Assert.AreEqual(validationMethod1Called, 1);
            Assert.AreEqual(validationCalls.Count, 1);
            Assert.AreEqual(validationCalls[0], "Method1");

            validationMethod1Called = 0;
            validationCalls.Clear();

            viewModel.Property.ChainValidationMethod
            (
                (
                    ModelProperty<string> property,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = true; validationMethod2Called++; validationCalls.Add("Method2"); }
            );
            Assert.IsNotNull(viewModel.Property.ValidationMethod);
            viewModel.Property.Validate();

            Assert.AreEqual(validationMethod1Called, 1);
            Assert.AreEqual(validationMethod2Called, 1);
            Assert.AreEqual(validationCalls.Count, 2);
            Assert.AreEqual(validationCalls[0], "Method1");
            Assert.AreEqual(validationCalls[1], "Method2");

            validationMethod1Called = 0;
            validationMethod2Called = 0;
            validationCalls.Clear();

            viewModel.Property.ChainValidationMethod
            (
                (
                    ModelProperty<string> property,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = true; validationMethod3Called++; validationCalls.Add("Method3"); }
            );
            Assert.IsNotNull(viewModel.Property.ValidationMethod);
            viewModel.Property.Validate();

            Assert.AreEqual(validationMethod1Called, 1);
            Assert.AreEqual(validationMethod2Called, 1);
            Assert.AreEqual(validationMethod3Called, 1);
            Assert.AreEqual(validationCalls.Count, 3);
            Assert.AreEqual(validationCalls[0], "Method1");
            Assert.AreEqual(validationCalls[1], "Method2");
            Assert.AreEqual(validationCalls[2], "Method3");

            viewModel.Property.ValidationMethod = null;
            viewModel.Property.ChainValidationMethod
            (
                (
                    ModelProperty<string> property,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = true; validationMethod1Called++; validationCalls.Add("Method1"); }
            );
            viewModel.Property.ChainValidationMethod
            (
                (
                    ModelProperty<string> property,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = false; validationMethod2Called++; validationCalls.Add("Method2"); }
            );
            viewModel.Property.ChainValidationMethod
            (
                (
                    ModelProperty<string> property,
                    ref IEnumerable<ValidationError> validationErrors,
                    ref Boolean isValid
                ) => { isValid = true; validationMethod3Called++; validationCalls.Add("Method3"); }
            );

            validationMethod1Called = 0;
            validationMethod2Called = 0;
            validationMethod3Called = 0;
            validationCalls.Clear();

            viewModel.Property.Validate();

            Assert.AreEqual(validationMethod1Called, 1);
            Assert.AreEqual(validationMethod2Called, 1);
            Assert.AreEqual(validationMethod3Called, 0);
            Assert.AreEqual(validationCalls.Count, 2);
            Assert.AreEqual(validationCalls[0], "Method1");
            Assert.AreEqual(validationCalls[1], "Method2");
        }

        [TestMethod]
        public void ReleaseObserversTest()
        {
            ModelForPropertyTesting viewModel = Creator.Create<ModelForPropertyTesting>();
            Boolean propertySignaled = false;

            viewModel.EnumProperty.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
            {
                propertySignaled = true;
            };

            viewModel.EnumProperty.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
            {
                propertySignaled = true;
            };

            viewModel.EnumProperty.Value = EnumForTesting.TestValue2;

            Assert.IsTrue(propertySignaled);
            propertySignaled = false;

            viewModel.EnumProperty.ReleaseObservers();
            viewModel.EnumProperty.Value = EnumForTesting.TestValue3;

            Assert.IsFalse(propertySignaled);
        }

        [TestMethod]
        public void CompareMethodTest()
        {
            ModelForPropertyTesting viewModel = Creator.Create<ModelForPropertyTesting>();
        }

        [TestMethod]
        public void CompareModelChildPropertyValuesTest()
        {
            ModelForPropertyTesting viewModel = Creator.Create<ModelForPropertyTesting>();

            viewModel.Int32Property.Value = 3;
            Assert.IsTrue(viewModel.IsDirty);
            viewModel.Int32Property.Commit();
            Assert.IsFalse(viewModel.Int32Property.IsDirty);
            viewModel.Int32Property.Value = 4;
            Assert.IsTrue(viewModel.IsDirty);
            viewModel.Int32Property.Commit();
            Assert.IsFalse(viewModel.Int32Property.IsDirty);
            viewModel.Int32Property.Value = viewModel.Int32Property.GetDefaultValue();
            Assert.IsTrue(viewModel.IsDirty);
            viewModel.Int32Property.Reset();
            Assert.IsFalse(viewModel.Int32Property.IsDirty);
            viewModel.Int32Property.Value = 4;
            Assert.IsFalse(viewModel.IsDirty);

            viewModel.NullableUInt32Property.Value = 4;
            Assert.IsTrue(viewModel.NullableUInt32Property.IsDirty);
            viewModel.NullableUInt32Property.Commit();
            Assert.IsFalse(viewModel.NullableUInt32Property.IsDirty);
            viewModel.NullableUInt32Property.Value = null;
            Assert.IsTrue(viewModel.NullableUInt32Property.IsDirty);
            viewModel.NullableUInt32Property.Commit();
            Assert.IsFalse(viewModel.NullableUInt32Property.IsDirty);
            viewModel.NullableUInt32Property.Value = null;
            Assert.IsFalse(viewModel.NullableUInt32Property.IsDirty);
            viewModel.NullableUInt32Property.Commit();
            Assert.IsFalse(viewModel.NullableUInt32Property.IsDirty);
            viewModel.NullableUInt32Property.Value = 4;
            viewModel.NullableUInt32Property.Commit();
            Assert.IsFalse(viewModel.NullableUInt32Property.IsDirty);
            viewModel.NullableUInt32Property.Value = 5;
            Assert.IsTrue(viewModel.NullableUInt32Property.IsDirty);
            viewModel.NullableUInt32Property.Commit();
            Assert.IsFalse(viewModel.NullableUInt32Property.IsDirty);
            viewModel.NullableUInt32Property.Value = 5;
            Assert.IsFalse(viewModel.NullableUInt32Property.IsDirty);

            viewModel.EnumProperty.Value = EnumForTesting.TestValue2;
            Assert.IsTrue(viewModel.IsDirty);
            viewModel.EnumProperty.Commit();
            Assert.IsFalse(viewModel.EnumProperty.IsDirty);
            viewModel.EnumProperty.Value = EnumForTesting.TestValue3;
            Assert.IsTrue(viewModel.IsDirty);
            viewModel.EnumProperty.Commit();
            Assert.IsFalse(viewModel.EnumProperty.IsDirty);
            viewModel.EnumProperty.Value = viewModel.EnumProperty.GetDefaultValue();
            Assert.IsTrue(viewModel.IsDirty);
            viewModel.EnumProperty.Reset();
            Assert.IsFalse(viewModel.EnumProperty.IsDirty);
            viewModel.EnumProperty.Value = EnumForTesting.TestValue3;
            Assert.IsFalse(viewModel.IsDirty);

            viewModel.NullableEnumProperty.Value = EnumForTesting.TestValue2;
            Assert.IsTrue(viewModel.NullableEnumProperty.IsDirty);
            viewModel.NullableEnumProperty.Commit();
            Assert.IsFalse(viewModel.NullableEnumProperty.IsDirty);
            viewModel.NullableEnumProperty.Value = null;
            Assert.IsTrue(viewModel.NullableEnumProperty.IsDirty);
            viewModel.NullableEnumProperty.Commit();
            Assert.IsFalse(viewModel.NullableEnumProperty.IsDirty);
            viewModel.NullableEnumProperty.Value = null;
            Assert.IsFalse(viewModel.NullableEnumProperty.IsDirty);
            viewModel.NullableEnumProperty.Commit();
            Assert.IsFalse(viewModel.NullableEnumProperty.IsDirty);
            viewModel.NullableEnumProperty.Value = EnumForTesting.TestValue2;
            viewModel.NullableEnumProperty.Commit();
            Assert.IsFalse(viewModel.NullableEnumProperty.IsDirty);
            viewModel.NullableEnumProperty.Value = EnumForTesting.TestValue3;
            Assert.IsTrue(viewModel.NullableEnumProperty.IsDirty);
            viewModel.NullableEnumProperty.Commit();
            Assert.IsFalse(viewModel.NullableEnumProperty.IsDirty);
            viewModel.NullableEnumProperty.Value = EnumForTesting.TestValue3;
            Assert.IsFalse(viewModel.NullableEnumProperty.IsDirty);

            viewModel.StringProperty.Value = "Value1";
            Assert.IsTrue(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Commit();
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = null;
            Assert.IsTrue(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Commit();
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = null;
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Commit();
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = "Value1";
            viewModel.StringProperty.Commit();
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = "Value2";
            Assert.IsTrue(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Commit();
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = "Value2";
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = String.Empty;
            Assert.IsTrue(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Commit();
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = null;
            Assert.IsTrue(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Commit();
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = String.Empty;
            Assert.IsTrue(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Commit();
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = String.Empty;
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Commit();
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = "Value3";
            viewModel.StringProperty.Commit();
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            viewModel.StringProperty.Value = new String("Value3".ToCharArray());
            Assert.IsFalse(viewModel.StringProperty.IsDirty);

            viewModel.StringArrayProperty.Value = new String[] { };
            Assert.IsTrue(viewModel.StringArrayProperty.IsDirty);
            viewModel.StringArrayProperty.Commit();
            Assert.IsFalse(viewModel.StringArrayProperty.IsDirty);
            viewModel.StringArrayProperty.Value = null;
            Assert.IsTrue(viewModel.StringArrayProperty.IsDirty);
            viewModel.StringArrayProperty.Commit();
            Assert.IsFalse(viewModel.StringArrayProperty.IsDirty);
            viewModel.StringArrayProperty.Value = null;
            Assert.IsFalse(viewModel.StringArrayProperty.IsDirty);
            String[] arrayValue = new String[] { };
            viewModel.StringArrayProperty.Value = arrayValue;
            Assert.IsTrue(viewModel.StringArrayProperty.IsDirty);
            viewModel.StringArrayProperty.Commit();
            Assert.IsFalse(viewModel.StringArrayProperty.IsDirty);
            viewModel.StringArrayProperty.Value = arrayValue;
            Assert.IsFalse(viewModel.StringArrayProperty.IsDirty);
            viewModel.StringArrayProperty.Value = new String[] { };
            Assert.IsTrue(viewModel.StringArrayProperty.IsDirty);

            viewModel.UnconstrainedInt32.Value = 4;
            Assert.IsTrue(viewModel.UnconstrainedInt32.IsDirty);
            viewModel.UnconstrainedInt32.Commit();
            Assert.IsFalse(viewModel.UnconstrainedInt32.IsDirty);
            viewModel.UnconstrainedInt32.Value = 0;
            Assert.IsTrue(viewModel.UnconstrainedInt32.IsDirty);
            viewModel.UnconstrainedInt32.Commit();
            Assert.IsFalse(viewModel.UnconstrainedInt32.IsDirty);
            viewModel.UnconstrainedInt32.Value = 0;
            Assert.IsFalse(viewModel.UnconstrainedInt32.IsDirty);
            viewModel.UnconstrainedInt32.Value = 3;
            viewModel.UnconstrainedInt32.Commit();
            Assert.IsFalse(viewModel.UnconstrainedInt32.IsDirty);
            viewModel.UnconstrainedInt32.Value = 3;
            Assert.IsFalse(viewModel.UnconstrainedInt32.IsDirty);
            viewModel.UnconstrainedInt32.Value = 4;
            Assert.IsTrue(viewModel.UnconstrainedInt32.IsDirty);

            viewModel.UnconstrainedNullableInt32.Value = 4;
            Assert.IsTrue(viewModel.UnconstrainedNullableInt32.IsDirty);
            viewModel.UnconstrainedNullableInt32.Commit();
            Assert.IsFalse(viewModel.UnconstrainedNullableInt32.IsDirty);
            viewModel.UnconstrainedNullableInt32.Value = null;
            Assert.IsTrue(viewModel.UnconstrainedNullableInt32.IsDirty);
            viewModel.UnconstrainedNullableInt32.Commit();
            Assert.IsFalse(viewModel.UnconstrainedNullableInt32.IsDirty);
            viewModel.UnconstrainedNullableInt32.Value = null;
            Assert.IsFalse(viewModel.UnconstrainedNullableInt32.IsDirty);
            viewModel.UnconstrainedNullableInt32.Value = 5;
            Assert.IsTrue(viewModel.UnconstrainedNullableInt32.IsDirty);
            viewModel.UnconstrainedNullableInt32.Commit();
            Assert.IsFalse(viewModel.UnconstrainedNullableInt32.IsDirty);
            viewModel.UnconstrainedNullableInt32.Value = 5;
            Assert.IsFalse(viewModel.UnconstrainedNullableInt32.IsDirty);
            viewModel.UnconstrainedNullableInt32.Value = 7;
            Assert.IsTrue(viewModel.UnconstrainedNullableInt32.IsDirty);

            viewModel.ChildModelProperty.Value = Creator.Create<ModelWithNoProperties>();
            Assert.IsTrue(viewModel.StringArrayProperty.IsDirty);
            Assert.IsFalse(viewModel.ChildModelProperty.Value.EqualsOverrideCalled);
            viewModel.ChildModelProperty.Commit();
            Assert.IsFalse(viewModel.ChildModelProperty.IsDirty);
            viewModel.ChildModelProperty.Value = null;
            Assert.IsTrue(viewModel.ChildModelProperty.IsDirty);
            viewModel.ChildModelProperty.Commit();
            Assert.IsFalse(viewModel.ChildModelProperty.IsDirty);
            viewModel.ChildModelProperty.Value = null;
            Assert.IsFalse(viewModel.ChildModelProperty.IsDirty);
            ModelWithNoProperties viewModelValue = Creator.Create<ModelWithNoProperties>();
            viewModel.ChildModelProperty.Value = viewModelValue;
            Assert.IsTrue(viewModel.ChildModelProperty.IsDirty);
            Assert.IsFalse(viewModel.ChildModelProperty.Value.EqualsOverrideCalled);
            viewModel.ChildModelProperty.Commit();
            Assert.IsFalse(viewModel.ChildModelProperty.IsDirty);
            viewModel.ChildModelProperty.Value = viewModelValue;
            Assert.IsFalse(viewModel.ChildModelProperty.Value.EqualsOverrideCalled);
            Assert.IsFalse(viewModel.ChildModelProperty.IsDirty);
            viewModel.ChildModelProperty.Value = Creator.Create<ModelWithNoProperties>();
            Assert.IsTrue(viewModel.ChildModelProperty.IsDirty);
            Assert.IsTrue(viewModel.ChildModelProperty.Value.EqualsOverrideCalled);

            ModelForValidationTesting viewModelB = Creator.Create<ModelForValidationTesting>();
            viewModelB.Property.Value = "Value1";
            Assert.IsTrue(viewModelB.ComputedStringProperty.IsDirty);
            viewModelB.Property.Value = null;
            Assert.IsFalse(viewModelB.ComputedStringProperty.IsDirty);
            viewModelB.Property.Value = "Value1";
            viewModelB.ComputedStringProperty.Commit();
            Assert.IsFalse(viewModelB.ComputedStringProperty.IsDirty);
            viewModelB.Property2.Value = "Value2";
            Assert.IsTrue(viewModelB.ComputedStringProperty.IsDirty);

        }

        [TestMethod]
        public void ModelPropertyCompareTest()
        {
            ModelForPropertyTesting viewModel = Creator.Create<ModelForPropertyTesting>();
            Boolean compareMethodCalled = false;
            Boolean returnTrue = false;

            viewModel.StringProperty.CompareMethod = delegate(String existingValue, String newValue)
            {
                compareMethodCalled = true;
                Boolean returnedValue = existingValue == newValue;

                if (returnTrue)
                {
                    returnedValue = true;
                }

                return returnedValue;
            };

            viewModel.StringProperty.Value = "Value1";
            Assert.IsTrue(compareMethodCalled);
            Assert.IsTrue(viewModel.StringProperty.IsDirty);

            viewModel.StringProperty.Reset();
            returnTrue = true;
            compareMethodCalled = false;
            viewModel.StringProperty.Value = "Value1";

            Assert.IsTrue(compareMethodCalled);
            Assert.IsFalse(viewModel.StringProperty.IsDirty);
            Assert.AreEqual(viewModel.StringProperty.Value, viewModel.StringProperty.GetDefaultValue());
        }

        [TestMethod]
        public void PropertyChangeCounterTest()
        {
            Creator.ModelFactory.PropertyChangeCounter = new PropertyChangeCounter();
            ModelForPropertyChangeCountTesting viewModelA = Creator.Create<ModelForPropertyChangeCountTesting>();
            viewModelA.ChildProperty.Value = Creator.Create<ModelForPropertyChangeCountTesting>();
            ModelForPropertyChangeCountTesting viewModelB = Creator.Create<ModelForPropertyChangeCountTesting>();
            viewModelB.ChildProperty.Value = Creator.Create<ModelForPropertyChangeCountTesting>();

            Assert.AreEqual(viewModelA.PropertyChangeCounter, Creator.ModelFactory.PropertyChangeCounter);
            Assert.AreEqual(viewModelA.ChildProperty.Value.PropertyChangeCounter, Creator.ModelFactory.PropertyChangeCounter);
            Assert.AreEqual(viewModelB.PropertyChangeCounter, Creator.ModelFactory.PropertyChangeCounter);
            Assert.AreEqual(viewModelB.ChildProperty.Value.PropertyChangeCounter, Creator.ModelFactory.PropertyChangeCounter);

            UInt64 currentChangeCount = 0;
            ModelPropertyBase lastProperty = null;

            Creator.ModelFactory.PropertyChangeCounter.AddObserver
            (
                delegate(UInt64 propertyChangeCount, ModelPropertyBase property)
                {
                    currentChangeCount = propertyChangeCount;
                    lastProperty = property;
                }
            );

            viewModelA.ChildProperty.Value.StringProperty.Value = "SomeValue";
            UInt64 lastChangeCount = currentChangeCount;
            Assert.IsTrue(currentChangeCount > 0);
            Assert.AreEqual(lastProperty, viewModelA.ChildProperty.Value.StringProperty);

            viewModelA.StringProperty.Value = "SomeValue";
            Assert.IsTrue(currentChangeCount > lastChangeCount);
            lastChangeCount = currentChangeCount;
            Assert.AreEqual(lastProperty, viewModelA.StringProperty);

            viewModelB.DecimalProperty.Value = 34;
            Assert.AreEqual(currentChangeCount, lastChangeCount);
            Assert.AreEqual(lastProperty, viewModelA.StringProperty);
        }

        [TestMethod]
        public void PropertyChangeCounterTest2()
        {
            Creator.ModelFactory.PropertyChangeCounter = new PropertyChangeCounter();
            ModelForPropertyChangeCountTesting viewModel = Creator.Create<ModelForPropertyChangeCountTesting>();

            PropertyCountChangeObserver observer1 = new PropertyCountChangeObserver();
            PropertyCountChangeObserver observer2 = new PropertyCountChangeObserver();
            PropertyCountChangeObserver observer3 = new PropertyCountChangeObserver();

            Action<UInt64, ModelPropertyBase> observer1Action = observer1.OnPropertyCountChange;
            Action<UInt64, ModelPropertyBase> observer1BAction = observer1.OnPropertyCountChange;
            Action<UInt64, ModelPropertyBase> observer2Action = observer2.OnPropertyCountChange;

            Creator.ModelFactory.PropertyChangeCounter.AddObserver(observer1Action);
            Creator.ModelFactory.PropertyChangeCounter.AddObserver(observer1BAction);
            Creator.ModelFactory.PropertyChangeCounter.AddObserver(observer2Action);

            viewModel.StringProperty.Value = "Value1";
            Assert.AreEqual(observer1.MethodCallCount, 1);
            Assert.AreEqual(observer2.MethodCallCount, 1);
            Assert.IsTrue(Creator.ModelFactory.PropertyChangeCounter.Observers.Contains(observer1Action));
            Assert.IsTrue(Creator.ModelFactory.PropertyChangeCounter.Observers.Contains(observer2Action));
            Assert.IsFalse(Creator.ModelFactory.PropertyChangeCounter.Observers.Contains(observer3.OnPropertyCountChange));

            observer2Action = null;

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            GC.WaitForPendingFinalizers();

            Assert.IsTrue(Creator.ModelFactory.PropertyChangeCounter.Observers.Contains(observer1Action));
            Assert.IsFalse(Creator.ModelFactory.PropertyChangeCounter.Observers.Contains(observer2Action));

            Action<UInt64, ModelPropertyBase> observer3Action = observer3.OnPropertyCountChange;
            Creator.ModelFactory.PropertyChangeCounter.AddObserver(observer3Action);
            Creator.ModelFactory.PropertyChangeCounter.RemoveObserver(observer1Action);

            Assert.IsTrue(Creator.ModelFactory.PropertyChangeCounter.Observers.Contains(observer3Action));
            Assert.IsFalse(Creator.ModelFactory.PropertyChangeCounter.Observers.Contains(observer1Action));

            Creator.ModelFactory.PropertyChangeCounter.RemoveObserver(observer2Action);
        }

        [TestMethod]
        public void AssignDefaultTest()
        {
            ModelForPropertyTesting viewModel = Creator.Create<ModelForPropertyTesting>();
            viewModel.StringProperty.Value = "NewValue";
            viewModel.StringProperty.Commit();
            viewModel.StringProperty.AssignDefaultValue();
            Assert.AreEqual(viewModel.StringProperty.Value, viewModel.StringProperty.GetDefaultValue());

            viewModel.ChildModelProperty.Value = Creator.Create<ModelWithNoProperties>();
            viewModel.StringProperty.Commit();
            viewModel.ChildModelProperty.AssignDefaultValue();
            Assert.AreEqual(viewModel.ChildModelProperty.Value, viewModel.ChildModelProperty.GetDefaultValue());

            viewModel.NullableEnumProperty.Value = EnumForTesting.TestValue2;
            viewModel.NullableEnumProperty.Commit();
            viewModel.NullableEnumProperty.AssignDefaultValue();
            Assert.AreEqual(viewModel.NullableEnumProperty.Value, viewModel.NullableEnumProperty.GetDefaultValue());
        }

        [TestMethod]
        public void ToStringTests()
        {
            IModelFactory factory = new ModelFactory();
            ModelForToStringTesting viewModel = factory.CreateModel<ModelForToStringTesting>();
            Assert.AreEqual(viewModel.EnumProperty.ToString(), EnumForTesting.TestValue1.ToString());
            Assert.AreEqual(viewModel.NullableEnumProperty.ToString(), null);
            Assert.AreEqual(viewModel.NullableInt32Property.ToString(), null);
            Assert.AreEqual(viewModel.StringProperty.ToString(), null);
            Assert.AreEqual(viewModel.ObjectProperty.ToString(), null);
            Assert.AreEqual(viewModel.DoubleProperty.ToString(), ((Double)0).ToString());
            Assert.AreEqual(viewModel.ModelProperty.ToString(), null);
            Assert.AreEqual(viewModel.ComputedProperty.ToString(), null);

            viewModel.EnumProperty.Value = EnumForTesting.TestValue2;
            viewModel.NullableEnumProperty.Value = EnumForTesting.TestValue4;
            viewModel.NullableInt32Property.Value = 5;
            viewModel.StringProperty.Value = "TheValue";
            viewModel.ObjectProperty.Value = 123;
            viewModel.DoubleProperty.Value = -1;
            viewModel.ModelProperty.Value = factory.CreateModel<ModelForToStringTesting>();
            viewModel.ComputedProperty.Value = "MyValue";

            Assert.AreEqual(viewModel.EnumProperty.ToString(), EnumForTesting.TestValue2.ToString());
            Assert.AreEqual(viewModel.NullableEnumProperty.ToString(), EnumForTesting.TestValue4.ToString());
            Assert.AreEqual(viewModel.NullableInt32Property.ToString(), "5");
            Assert.AreEqual(viewModel.StringProperty.ToString(), "TheValue");
            Assert.AreEqual(viewModel.ObjectProperty.ToString(), "123");
            Assert.AreEqual(viewModel.DoubleProperty.ToString(), "-1");
            Assert.AreEqual(viewModel.ModelProperty.ToString(), viewModel.ModelProperty.Value.ToString());
            Assert.AreEqual(viewModel.ComputedProperty.ToString(), viewModel.ComputedProperty.Value.ToString());
        }

        [TestMethod]
        public void IsDirtyTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();

            Assert.IsFalse(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);

            viewModel.IntProperty1.Value = 3;
            Assert.AreEqual(viewModel.IntProperty1.Value, 3);

            Assert.IsTrue(viewModel.IntProperty1.IsDirty);
            Assert.IsFalse(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);
            Assert.AreEqual(viewModel.DirtyPropertyCount, 0);

            viewModel.IntProperty2.Value = 4;
            Assert.AreEqual(viewModel.IntProperty2.Value, 4);

            Assert.IsTrue(viewModel.IntProperty2.IsDirty);
            Assert.IsTrue(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);
            Assert.AreEqual(viewModel.DirtyPropertyCount, 1);

            viewModel.IntProperty1.Value = viewModel.IntProperty1.GetDefaultValue();
            Assert.AreEqual(viewModel.IntProperty1.Value, viewModel.IntProperty1.GetDefaultValue());

            Assert.IsFalse(viewModel.IntProperty1.IsDirty);
            Assert.IsTrue(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);
            Assert.AreEqual(viewModel.DirtyPropertyCount, 1);

            viewModel.IntProperty3.Value = 5;
            Assert.AreEqual(viewModel.IntProperty3.Value, 5);

            Assert.IsFalse(viewModel.IntProperty3.IsDirty);
            Assert.IsTrue(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);
            Assert.AreEqual(viewModel.DirtyPropertyCount, 1);

            viewModel.IntProperty4.Value = 6;
            Assert.AreEqual(viewModel.IntProperty4.Value, 6);

            Assert.IsTrue(viewModel.IntProperty4.IsDirty);
            Assert.IsTrue(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);
            Assert.AreEqual(viewModel.DirtyPropertyCount, 2);

            viewModel.IntProperty4.Value = 6;
            Assert.AreEqual(viewModel.IntProperty4.Value, 6);

            Assert.IsTrue(viewModel.IntProperty4.IsDirty);
            Assert.IsTrue(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);
            Assert.AreEqual(viewModel.DirtyPropertyCount, 2);

            viewModel.IntProperty2.Value = viewModel.IntProperty2.GetDefaultValue();
            Assert.AreEqual(viewModel.IntProperty2.Value, viewModel.IntProperty2.GetDefaultValue());

            Assert.IsFalse(viewModel.IntProperty2.IsDirty);
            Assert.IsTrue(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);
            Assert.AreEqual(viewModel.DirtyPropertyCount, 1);

            viewModel.IntProperty4.Value = viewModel.IntProperty4.GetDefaultValue();
            Assert.AreEqual(viewModel.IntProperty4.Value, viewModel.IntProperty4.GetDefaultValue());

            Assert.IsFalse(viewModel.IntProperty4.IsDirty);
            Assert.IsFalse(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);
            Assert.AreEqual(viewModel.DirtyPropertyCount, 0);

            viewModel.IntProperty4.Value = viewModel.IntProperty4.GetDefaultValue();
            Assert.AreEqual(viewModel.IntProperty4.Value, viewModel.IntProperty4.GetDefaultValue());

            Assert.IsFalse(viewModel.IntProperty4.IsDirty);
            Assert.IsFalse(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);
            Assert.AreEqual(viewModel.DirtyPropertyCount, 0);

            viewModel.IntProperty5.Value = 7;
            Assert.AreEqual(viewModel.IntProperty5.Value, 7);

            Assert.IsFalse(viewModel.IntProperty5.IsDirty);
            Assert.IsFalse(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);
            Assert.AreEqual(viewModel.DirtyPropertyCount, 0);
        }

        [TestMethod]
        public void MultipleIsDirtyWithinProperties()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child.Value = Creator.Create<ModelForPropertyTestingC>();

            Assert.IsFalse(viewModel.IsDirty);
            Assert.IsFalse(viewModel.IsDirtyWithin);

            viewModel.Child.Value.Child.Value.IntProperty2.Value = 3;
            Assert.IsTrue(viewModel.IsDirtyWithin);

            viewModel.Child2.Value.Child.Value.IntProperty2.Value = 4;
            Assert.IsTrue(viewModel.IsDirtyWithin);

            viewModel.Child.Value.Child.Value.IntProperty2.Reset();
            Assert.IsTrue(viewModel.IsDirtyWithin);

            viewModel.Child2.Value.Child.Value.IntProperty2.Reset();
            Assert.IsFalse(viewModel.IsDirtyWithin);
        }

        [TestMethod]
        public void CleanParent_CleanChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value);
        }

        [TestMethod]
        public void CleanParent_DirtyChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 11;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 11;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);
        }

        [TestMethod]
        public void CleanParent_DirtyWithinChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 10;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 10;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);
        }

        [TestMethod]
        public void CleanParent_DirtyWithinAndDirtyChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 9;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 9;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);
        }

        [TestMethod]
        public void DirtyParent_CleanChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            AssignCleanChild(viewModel, viewModel);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value);
        }

        [TestMethod]
        public void DirtyParent_DirtyChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 8;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 8;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);
        }

        [TestMethod]
        public void DirtyParent_DirtyWithinChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 9;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 9;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);
        }

        [TestMethod]
        public void DirtyParent_DirtyWithinAndDirtyChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 5;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 5;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);
        }

        [TestMethod]
        public void DirtyWithinParent_CleanChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 3;
            AssignCleanChild(viewModel, viewModel);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value);
        }

        [TestMethod]
        public void DirtyWithinParent_DirtyChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 8;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 8;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);
        }

        [TestMethod]
        public void DirtyWithinParent_DirtyWithinChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 5;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 5;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);
        }

        [TestMethod]
        public void DirtyWithinParent_DirtyWithinAndDirtyChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);
        }

        [TestMethod]
        public void DirtyWithinAndDirtyParent_CleanChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 3;
            AssignCleanChild(viewModel, viewModel);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignCleanChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value);
        }

        [TestMethod]
        public void DirtyWithinAndDirtyParent_DirtyChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, false);
        }

        [TestMethod]
        public void DirtyWithinAndDirtyParent_DirtyWithinChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 5;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 6;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 5;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 6;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, false, true);
        }

        [TestMethod]
        public void DirtyWithinAndDirtyParent_DirtyWithinAndDirtyChildTest()
        {
            ModelForPropertyTestingC viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.IntProperty2.Value = 2;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);

            viewModel = Creator.Create<ModelForPropertyTestingC>();
            viewModel.IntProperty2.Value = -4;
            viewModel.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.IntProperty2.Value = 3;
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child.Value = Creator.Create<ModelForPropertyTestingC>();
            viewModel.Child2.Value.Child2.Value.Child2.Value.Child.Value.IntProperty2.Value = 3;
            AssignDirtyChild(viewModel, viewModel.Child2.Value.Child2.Value.Child2.Value, true, true);
        }

        private static void AssignCleanChild(ModelForPropertyTestingC rootParent, ModelForPropertyTestingC directParent)
        {
            Boolean isDirtyChanged = false;
            Boolean isInvalidChanged = false;
            Boolean isDirtyWithinChanged = false;
            Boolean isInvalidWithinChanged = false;

            Boolean rootParentIsDirty = rootParent.IsDirty;
            Boolean rootParentIsDirtyWithin = rootParent.IsDirtyWithin;
            Boolean rootParentIsInvalid = rootParent.IsInvalid;
            Boolean rootParentIsInvalidWithin = rootParent.IsInvalidWithin;

            rootParent.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs args)
            {
                isDirtyChanged = isDirtyChanged || args.PropertyName == "IsDirty";
                isInvalidChanged = isInvalidChanged || args.PropertyName == "IsInvalid";
                isDirtyWithinChanged = isDirtyWithinChanged || args.PropertyName == "IsDirtyWithin";
                isInvalidWithinChanged = isInvalidWithinChanged || args.PropertyName == "IsInvalidWithin";
            };

            //Initial assignment
            ModelForPropertyTestingC child1 = Creator.Create<ModelForPropertyTestingC>();
            directParent.Child.Value = child1;

            Assert.IsFalse(child1.IsDirty);
            Assert.IsFalse(child1.IsDirtyWithin);
            Assert.IsFalse(child1.IsInvalid);
            Assert.IsFalse(child1.IsInvalidWithin);
            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, rootParentIsDirtyWithin);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, rootParentIsInvalidWithin);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsFalse(isDirtyWithinChanged);
            Assert.IsFalse(isInvalidChanged);
            Assert.IsFalse(isInvalidWithinChanged);

            //Swap assignment
            ModelForPropertyTestingC child2 = Creator.Create<ModelForPropertyTestingC>();
            directParent.Child.Value = child2;

            Assert.IsFalse(child2.IsDirty);
            Assert.IsFalse(child2.IsDirtyWithin);
            Assert.IsFalse(child2.IsInvalid);
            Assert.IsFalse(child2.IsInvalidWithin);
            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, rootParentIsDirtyWithin);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, rootParentIsInvalidWithin);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsFalse(isDirtyWithinChanged);
            Assert.IsFalse(isInvalidChanged);
            Assert.IsFalse(isInvalidWithinChanged);

            //Duplicate assignment
            directParent.Child.Value = child2;

            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, rootParentIsDirtyWithin);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, rootParentIsInvalidWithin);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsFalse(isDirtyWithinChanged);
            Assert.IsFalse(isInvalidChanged);
            Assert.IsFalse(isInvalidWithinChanged);

            //Null assignment
            directParent.Child.Value = null;

            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, rootParentIsDirtyWithin);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, rootParentIsInvalidWithin);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsFalse(isDirtyWithinChanged);
            Assert.IsFalse(isInvalidChanged);
            Assert.IsFalse(isInvalidWithinChanged);

            //Original assignment
            directParent.Child.Value = child1;

            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, rootParentIsDirtyWithin);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, rootParentIsInvalidWithin);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsFalse(isDirtyWithinChanged);
            Assert.IsFalse(isInvalidChanged);
            Assert.IsFalse(isInvalidWithinChanged);

            //Make child dirty
            child1.IntProperty2.Value = -1;

            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, true);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, true);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsTrue((rootParentIsDirtyWithin && !isDirtyWithinChanged) || isDirtyWithinChanged);
            Assert.IsFalse(isInvalidChanged);
            Assert.IsTrue((rootParentIsInvalidWithin && !isInvalidWithinChanged) || isInvalidWithinChanged);
        }

        private static void AssignDirtyChild
        (
            ModelForPropertyTestingC rootParent,
            ModelForPropertyTestingC directParent,
            Boolean makeTestModelsDirty,
            Boolean makeTestModelsDirtyWithin
        )
        {
            Boolean isDirtyChanged = false;
            Boolean isInvalidChanged = false;
            Boolean isDirtyWithinChanged = false;
            Boolean isInvalidWithinChanged = false;

            Boolean rootParentIsDirty = rootParent.IsDirty;
            Boolean rootParentIsDirtyWithin = rootParent.IsDirtyWithin;
            Boolean rootParentIsInvalid = rootParent.IsInvalid;
            Boolean rootParentIsInvalidWithin = rootParent.IsInvalidWithin;

            rootParent.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs args)
            {
                isDirtyChanged = isDirtyChanged || args.PropertyName == "IsDirty";
                isInvalidChanged = isInvalidChanged || args.PropertyName == "IsInvalid";
                isDirtyWithinChanged = isDirtyWithinChanged || args.PropertyName == "IsDirtyWithin";
                isInvalidWithinChanged = isInvalidWithinChanged || args.PropertyName == "IsInvalidWithin";
            };

            //Initial assignment
            ModelForPropertyTestingC child1 = Creator.Create<ModelForPropertyTestingC>();

            if (makeTestModelsDirty)
            {
                child1.IntProperty2.Value = 2;
            }

            if (makeTestModelsDirtyWithin)
            {
                child1.Child.Value = Creator.Create<ModelForPropertyTestingC>();
                child1.Child.Value.IntProperty2.Value = 3;
            }

            directParent.Child.Value = child1;

            Assert.AreEqual(child1.IsDirty, makeTestModelsDirty);
            Assert.AreEqual(child1.IsDirtyWithin, makeTestModelsDirtyWithin);
            Assert.AreEqual(child1.IsInvalid, makeTestModelsDirty);
            Assert.AreEqual(child1.IsInvalidWithin, makeTestModelsDirtyWithin);
            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, true);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, true);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsTrue
            (
                (rootParentIsDirtyWithin && !isDirtyWithinChanged) ||
                isDirtyWithinChanged
            );
            Assert.IsFalse(isInvalidChanged);
            Assert.IsTrue
            (
                (rootParentIsInvalidWithin && !isInvalidWithinChanged) ||
                isInvalidWithinChanged
            );

            isDirtyWithinChanged = false;
            isInvalidWithinChanged = false;

            //Swap assignment
            ModelForPropertyTestingC child2 = Creator.Create<ModelForPropertyTestingC>();

            if (makeTestModelsDirty)
            {
                child2.IntProperty2.Value = 2;
            }

            if (makeTestModelsDirtyWithin)
            {
                child2.Child.Value = Creator.Create<ModelForPropertyTestingC>();
                child2.Child.Value.IntProperty2.Value = 3;
            }

            directParent.Child.Value = child2;

            Assert.AreEqual(child2.IsDirty, makeTestModelsDirty);
            Assert.AreEqual(child2.IsDirtyWithin, makeTestModelsDirtyWithin);
            Assert.AreEqual(child2.IsInvalid, makeTestModelsDirty);
            Assert.AreEqual(child2.IsInvalidWithin, makeTestModelsDirtyWithin);
            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, true);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, true);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsFalse(isDirtyWithinChanged);
            Assert.IsFalse(isInvalidChanged);
            Assert.IsFalse(isInvalidWithinChanged);

            //Duplicate assignment
            directParent.Child.Value = child2;

            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, true);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, true);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsFalse(isDirtyWithinChanged);
            Assert.IsFalse(isInvalidChanged);
            Assert.IsFalse(isInvalidWithinChanged);

            //Null assignment
            directParent.Child.Value = null;

            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, rootParentIsDirtyWithin);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, rootParentIsInvalidWithin);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsTrue
            (
                (rootParentIsDirtyWithin && !isDirtyWithinChanged) ||
                isDirtyWithinChanged
            );
            Assert.IsFalse(isInvalidChanged);
            Assert.IsTrue
            (
                (rootParentIsInvalidWithin && !isInvalidWithinChanged) ||
                isInvalidWithinChanged
            );

            isDirtyWithinChanged = false;
            isInvalidWithinChanged = false;

            //Original assignment
            directParent.Child.Value = child1;

            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, true);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, true);
            Assert.IsFalse(isDirtyChanged);
            Assert.IsTrue
            (
                (rootParentIsDirtyWithin && !isDirtyWithinChanged) ||
                isDirtyWithinChanged
            );
            Assert.IsFalse(isInvalidChanged);
            Assert.IsTrue
            (
                (rootParentIsInvalidWithin && !isInvalidWithinChanged) ||
                isInvalidWithinChanged
            );

            isDirtyWithinChanged = false;
            isInvalidWithinChanged = false;

            //Clean child assignment
            ModelForPropertyTestingC child3 = Creator.Create<ModelForPropertyTestingC>();
            directParent.Child.Value = child3;

            Assert.IsFalse(child3.IsDirty);
            Assert.IsFalse(child3.IsDirtyWithin);
            Assert.IsFalse(child3.IsInvalid);
            Assert.IsFalse(child3.IsInvalidWithin);
            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, rootParentIsDirtyWithin);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, rootParentIsInvalidWithin);
            Assert.IsTrue
            (
                (rootParentIsDirtyWithin && !isDirtyWithinChanged) ||
                isDirtyWithinChanged
            );
            Assert.IsFalse(isInvalidChanged);
            Assert.IsTrue
            (
                (rootParentIsInvalidWithin && !isInvalidWithinChanged) ||
                isInvalidWithinChanged
            );

            isDirtyWithinChanged = false;
            isInvalidWithinChanged = false;

            //Make child dirty
            child3.IntProperty2.Value = 5;

            Assert.IsTrue(child3.IsDirty);
            Assert.IsFalse(child3.IsDirtyWithin);
            Assert.IsTrue(child3.IsInvalid);
            Assert.IsFalse(child3.IsInvalidWithin);
            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, true);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, true);
            Assert.IsTrue
            (
                (rootParentIsDirtyWithin && !isDirtyWithinChanged) ||
                isDirtyWithinChanged
            );
            Assert.IsFalse(isInvalidChanged);
            Assert.IsTrue
            (
                (rootParentIsInvalidWithin && !isInvalidWithinChanged) ||
                isInvalidWithinChanged
            );

            isDirtyWithinChanged = false;
            isInvalidWithinChanged = false;

            //Make child clean
            child3.IntProperty2.Value = child3.IntProperty2.GetDefaultValue();

            Assert.IsFalse(child3.IsDirty);
            Assert.IsFalse(child3.IsDirtyWithin);
            Assert.IsFalse(child3.IsInvalid);
            Assert.IsFalse(child3.IsInvalidWithin);
            Assert.AreEqual(rootParent.IsDirty, rootParentIsDirty);
            Assert.AreEqual(rootParent.IsDirtyWithin, rootParentIsDirtyWithin);
            Assert.AreEqual(rootParent.IsInvalid, rootParentIsInvalid);
            Assert.AreEqual(rootParent.IsInvalidWithin, rootParentIsInvalidWithin);
            Assert.IsTrue
            (
                (rootParentIsDirtyWithin && !isDirtyWithinChanged) ||
                isDirtyWithinChanged
            );
            Assert.IsFalse(isInvalidChanged);
            Assert.IsTrue
            (
                (rootParentIsInvalidWithin && !isInvalidWithinChanged) ||
                isInvalidWithinChanged
            );
        }

        [TestMethod]
        public void ParentAssignmentTest()
        {
            ModelForPropertyTestingC parent = Creator.Create<ModelForPropertyTestingC>();
            ModelForPropertyTestingC childA = Creator.Create<ModelForPropertyTestingC>();
            ModelForPropertyTestingC childB = Creator.Create<ModelForPropertyTestingC>();
            ModelForPropertyTestingC childC = Creator.Create<ModelForPropertyTestingC>();

            Assert.IsNull(parent.Parent);
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childB.Parent);
            AssertModelHasNoParent(childA);
            AssertModelHasNoParent(childB);
            AssertModelHasNoParent(childC);

            parent.Child3.Value = childA;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);

            //Duplicate assignment shouldn't fail
            parent.Child3.Value = childA;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);

            parent.Child3.Value = null;
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);

            parent.Child3.Value = childA;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);

            parent.Child3.Value = childB;
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childB);

            parent.Child3.Value = childA;
            Assert.IsNull(childB.Parent);
            Assert.IsNull(childB.ParentProperty);
            AssertModelHasNoParent(childB);
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);

            parent.Child3.Commit();
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childA);

            //Test duplicate assignment does not fail once value is committed
            parent.Child3.Value = childA;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childA);

            parent.Child3.Commit();
            AssertModelIsCommittedToParent(childA);

            childA.IntProperty2.Value = 12;

            parent.Child3.Value = childB;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childB);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childC;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childA);
            Assert.IsNull(childB.Parent);
            Assert.IsNull(childB.ParentProperty);
            AssertModelHasNoParent(childB);
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childC);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childA;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childA);
            Assert.IsNull(childC.Parent);
            Assert.IsNull(childC.ParentProperty);
            AssertModelHasNoParent(childC);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            childB.IntProperty2.Value = 23;

            parent.Child3.Value = childB;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childB);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Commit();
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childB);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = childA;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childB);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            childC.IntProperty2.Value = 23;

            parent.Child3.Value = childC;
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childB);
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childC);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = childB;
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.IsNull(childC.Parent);
            Assert.IsNull(childC.ParentProperty);
            AssertModelHasNoParent(childC);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childB);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            childB.IntProperty2.Value = childB.IntProperty2.GetDefaultValue();

            parent.Child3.Value = childA;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childB);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = childC;
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childC);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childB);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = childB;
            Assert.IsNull(childC.Parent);
            Assert.IsNull(childC.ParentProperty);
            AssertModelHasNoParent(childC);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childB);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            childA.IntProperty2.Value = childA.IntProperty2.GetDefaultValue();
            childC.IntProperty2.Value = childC.IntProperty2.GetDefaultValue();

            parent.Child3.Value = childC;
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childC);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childB);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childA;
            Assert.IsNull(childC.Parent);
            Assert.IsNull(childC.ParentProperty);
            AssertModelHasNoParent(childC);
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childB);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childB;
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childB);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            childB.IntProperty2.Value = 12;
            childA.IntProperty2.Value = childA.IntProperty2.GetDefaultValue();

            parent.Child3.Value = childC;
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childC);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childB);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childA;
            Assert.IsNull(childC.Parent);
            Assert.IsNull(childC.ParentProperty);
            AssertModelHasNoParent(childC);
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childB);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childB;
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childB);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = childC;
            parent.Child3.Commit();
            AssertModelHasNoParent(childB);
            AssertModelIsCommittedToParent(childC);

            parent.Child3.Value = childB;
            Assert.AreEqual(childB.Parent, parent);
            Assert.AreEqual(childB.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childB);
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childC);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = childA;
            Assert.IsNull(childB.Parent);
            Assert.IsNull(childB.ParentProperty);
            AssertModelHasNoParent(childB);
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childC);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = null;
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childC);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childC;
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childC);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            childC.IntProperty2.Value = 5;

            parent.Child3.Value = null;
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childC);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Commit();
            Assert.IsNull(childC.Parent);
            Assert.IsNull(childC.ParentProperty);
            AssertModelHasNoParent(childC);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Commit();

            parent.Child3.Value = childC;
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childC);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Commit();
            AssertModelIsCommittedToParent(childC);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = null;
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childC);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Commit();

            Assert.IsNull(childC.Parent);
            Assert.IsNull(childC.ParentProperty);
            AssertModelHasNoParent(childC);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childC;
            parent.Child3.Commit();
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childC);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = childA;
            parent.Child3.Commit();
            Assert.IsNull(childC.Parent);
            Assert.IsNull(childC.ParentProperty);
            AssertModelHasNoParent(childC);
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childA);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childC;
            parent.Child3.Commit();
            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.AreEqual(childC.Parent, parent);
            Assert.AreEqual(childC.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childC);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            childC.IntProperty2.Value = childC.IntProperty2.GetDefaultValue();
            parent.Child3.Value = childA;
            parent.Child3.Commit();
            Assert.IsNull(childC.Parent);
            Assert.IsNull(childC.ParentProperty);
            AssertModelHasNoParent(childC);
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childA);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            childC.IntProperty2.Value = childC.IntProperty2.GetDefaultValue();
            parent.Child3.Value = childA;
            parent.Child3.Commit();
            parent.Child3.Commit();
            Assert.IsNull(childC.Parent);
            Assert.IsNull(childC.ParentProperty);
            AssertModelHasNoParent(childC);
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childA);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = null;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childA);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childA;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childA);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            childA.IntProperty2.Value = 45;

            parent.Child3.Value = null;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsRemovedFromParent(childA);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childA;
            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsCommittedToParent(childA);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = null;
            parent.Child3.Commit();
            parent.Child3.Commit();

            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childA;

            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = null;

            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            childA.IntProperty2.Value = childA.IntProperty2.GetDefaultValue();
            parent.Child3.Value = childA;

            Assert.AreEqual(childA.Parent, parent);
            Assert.AreEqual(childA.ParentProperty, parent.Child3);
            AssertModelIsAssignedToParent(childA);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = null;

            Assert.IsNull(childA.Parent);
            Assert.IsNull(childA.ParentProperty);
            AssertModelHasNoParent(childA);
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);

            parent.Child3.Value = childA;
            parent.Child3.Commit();
            childA.IntProperty2.Value = 2;
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);

            parent.Child3.Value = null;
            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);
            AssertModelIsRemovedFromParent(childA);

            childA.IntProperty2.Value = childA.IntProperty2.GetDefaultValue();

            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);
            AssertModelIsRemovedFromParent(childA);

            childA.IntProperty2.Value = 45;

            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);
            AssertModelIsRemovedFromParent(childA);

            childA.IntProperty2.Value = childA.IntProperty2.GetDefaultValue();

            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);
            AssertModelIsRemovedFromParent(childA);

            childA.IntProperty2.Value = -12;

            Assert.IsFalse(parent.IsDirtyWithin);
            Assert.IsFalse(parent.IsInvalidWithin);
            AssertModelIsRemovedFromParent(childA);

            parent.Child3.Value = childA;
            Assert.IsTrue(parent.IsDirtyWithin);
            Assert.IsTrue(parent.IsInvalidWithin);
            AssertModelIsCommittedToParent(childA);
        }

        private static void AssertModelIsAssignedToParent(ModelForPropertyTestingC viewModel)
        {
            Assert.IsFalse(viewModel.IsRemovedFromParent);
            Assert.IsTrue(viewModel.IsAssignedToParentProperty);
            Assert.IsFalse(viewModel.IsCommittedToParentProperty);
            Assert.IsFalse(viewModel.IsRemovedFromParentProperty);
        }

        private static void AssertModelIsCommittedToParent(ModelForPropertyTestingC viewModel)
        {
            Assert.IsFalse(viewModel.IsRemovedFromParent);
            Assert.IsFalse(viewModel.IsAssignedToParentProperty);
            Assert.IsTrue(viewModel.IsCommittedToParentProperty);
            Assert.IsFalse(viewModel.IsRemovedFromParentProperty);
        }

        private static void AssertModelIsRemovedFromParent(ModelForPropertyTestingC viewModel)
        {
            Assert.IsTrue(viewModel.IsRemovedFromParent);
            Assert.IsFalse(viewModel.IsAssignedToParentProperty);
            Assert.IsFalse(viewModel.IsCommittedToParentProperty);
            Assert.IsTrue(viewModel.IsRemovedFromParentProperty);
        }

        private static void AssertModelHasNoParent(ModelForPropertyTestingC viewModel)
        {
            Assert.IsFalse(viewModel.IsRemovedFromParent);
            Assert.IsFalse(viewModel.IsAssignedToParentProperty);
            Assert.IsFalse(viewModel.IsCommittedToParentProperty);
            Assert.IsFalse(viewModel.IsRemovedFromParentProperty);
        }

        [TestMethod]
        public void SimplePropertyAssignment_EventSequenceTest()
        {
            ModelForEventSequenceTesting viewModelA = Creator.Create<ModelForEventSequenceTesting>();
            ModelForEventSequenceTesting viewModelB = Creator.Create<ModelForEventSequenceTesting>();
            ModelForEventSequenceTesting viewModelC = Creator.Create<ModelForEventSequenceTesting>();

            CallCounter counter = new CallCounter();

            viewModelA.Counter = counter;
            viewModelB.Counter = counter;
            viewModelC.Counter = counter;
            viewModelA.Child.AssignCommitted(viewModelB);
            viewModelB.Child.AssignCommitted(viewModelC);

            Dictionary<Int32, String> viewModelAChanges = new Dictionary<Int32, String>();
            Dictionary<Int32, String> viewModelAPropertyChanges = new Dictionary<Int32, String>();

            viewModelA.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
            {
                viewModelAChanges[counter.Index++] = e.PropertyName;
            };

            viewModelA.Property.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
            {
                viewModelAPropertyChanges[counter.Index++] = e.PropertyName;
            };

            Dictionary<Int32, String> viewModelBChanges = new Dictionary<Int32, String>();
            Dictionary<Int32, String> viewModelBPropertyChanges = new Dictionary<Int32, String>();

            viewModelB.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
            {
                viewModelBChanges[counter.Index++] = e.PropertyName;
            };

            viewModelB.Property.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
            {
                viewModelBPropertyChanges[counter.Index++] = e.PropertyName;
            };

            Dictionary<Int32, String> viewModelCChanges = new Dictionary<Int32, String>();
            Dictionary<Int32, String> viewModelCPropertyChanges = new Dictionary<Int32, String>();

            viewModelC.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
            {
                viewModelCChanges[counter.Index++] = e.PropertyName;
            };

            viewModelC.Property.PropertyChanged += delegate(Object sender, PropertyChangedEventArgs e)
            {
                viewModelCPropertyChanges[counter.Index++] = e.PropertyName;
            };

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            InitialAssignmentTest
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            DuplicateAssignmentTest
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            DifferentNonDefaultAssignmentTest
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetTest
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            DuplicateResetTest
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            CommitTest
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            DuplicateCommitTest
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            AssignCommittedTest
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            DuplicateAssignCommittedTest
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            AssignDefaultValueAsCommittedTest
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );
        }

        private static void ResetEventSequenceTestObjects
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelA.ResetIndexCounters();
            viewModelAChanges.Clear();
            viewModelAPropertyChanges.Clear();
            viewModelB.ResetIndexCounters();
            viewModelBChanges.Clear();
            viewModelBPropertyChanges.Clear();
            viewModelC.ResetIndexCounters();
            viewModelCChanges.Clear();
            viewModelCPropertyChanges.Clear();
            counter.Index = 0;
        }

        private static void InitialAssignmentTest
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelC.Property.Value = "Value1";

            Int32 callIndex = 0;
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "Value");
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "IsDefault");
            Assert.AreEqual(viewModelC.OnPropertyIsDefaultChangedIndex.Value, callIndex++);

            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "IsDirty");
            Assert.AreEqual(viewModelC.OnPropertyIsDirtyChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelCChanges[callIndex++], "DirtyPropertyCount");
            Assert.AreEqual(viewModelCChanges[callIndex++], "IsDirty");
            Assert.AreEqual(viewModelC.OnIsDirtyChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelBChanges[callIndex++], "IsDirtyWithin");
            Assert.AreEqual(viewModelB.OnIsDirtyWithinChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelAChanges[callIndex++], "IsDirtyWithin");
            Assert.AreEqual(viewModelA.OnIsDirtyWithinChangedIndex.Value, callIndex++);

            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "ValidationErrors");
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "IsInvalid");
            Assert.AreEqual(viewModelC.OnPropertyIsInvalidChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelCChanges[callIndex++], "InvalidPropertyCount");
            Assert.AreEqual(viewModelCChanges[callIndex++], "IsInvalid");
            Assert.AreEqual(viewModelC.OnIsInvalidChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelBChanges[callIndex++], "IsInvalidWithin");
            Assert.AreEqual(viewModelB.OnIsInvalidWithinChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelAChanges[callIndex++], "IsInvalidWithin");
            Assert.AreEqual(viewModelA.OnIsInvalidWithinChangedIndex.Value, callIndex++);

            Assert.AreEqual(viewModelC.OnPropertyValueChangedIndex.Value, callIndex++);
            Assert.AreEqual(callIndex, counter.Index);
        }

        private static void DuplicateAssignmentTest
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelC.Property.Value = "Value1";
            Assert.AreEqual(counter.Index, 0);
        }

        private static void DifferentNonDefaultAssignmentTest
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelC.Property.Value = "Value2";

            Int32 callIndex = 0;
            Assert.AreEqual(viewModelCPropertyChanges.Count, 1);
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "Value");
            Assert.AreEqual(viewModelC.OnPropertyValueChangedIndex.Value, callIndex++);
            Assert.AreEqual(callIndex, counter.Index);
        }

        private static void ResetTest
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelC.Property.Reset();

            Int32 callIndex = 0;
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "Value");
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "IsDefault");
            Assert.AreEqual(viewModelC.OnPropertyIsDefaultChangedIndex.Value, callIndex++);

            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "IsDirty");
            Assert.AreEqual(viewModelC.OnPropertyIsDirtyChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelCChanges[callIndex++], "DirtyPropertyCount");
            Assert.AreEqual(viewModelCChanges[callIndex++], "IsDirty");
            Assert.AreEqual(viewModelC.OnIsDirtyChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelBChanges[callIndex++], "IsDirtyWithin");
            Assert.AreEqual(viewModelB.OnIsDirtyWithinChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelAChanges[callIndex++], "IsDirtyWithin");
            Assert.AreEqual(viewModelA.OnIsDirtyWithinChangedIndex.Value, callIndex++);

            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "ValidationErrors");
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "IsInvalid");
            Assert.AreEqual(viewModelC.OnPropertyIsInvalidChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelCChanges[callIndex++], "InvalidPropertyCount");
            Assert.AreEqual(viewModelCChanges[callIndex++], "IsInvalid");
            Assert.AreEqual(viewModelC.OnIsInvalidChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelBChanges[callIndex++], "IsInvalidWithin");
            Assert.AreEqual(viewModelB.OnIsInvalidWithinChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelAChanges[callIndex++], "IsInvalidWithin");
            Assert.AreEqual(viewModelA.OnIsInvalidWithinChangedIndex.Value, callIndex++);

            Assert.AreEqual(viewModelC.OnPropertyValueChangedIndex.Value, callIndex++);
            Assert.AreEqual(callIndex, counter.Index);
        }

        private static void DuplicateResetTest
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelC.Property.Reset();
            Assert.AreEqual(counter.Index, 0);
        }

        private static void CommitTest
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelC.Property.Value = "Value2";

            ResetEventSequenceTestObjects
            (
                viewModelA, viewModelAChanges, viewModelAPropertyChanges,
                viewModelB, viewModelBChanges, viewModelBPropertyChanges,
                viewModelC, viewModelCChanges, viewModelCPropertyChanges,
                counter
            );

            viewModelC.Property.Commit();

            Int32 callIndex = 0;
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "CommittedValue");
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "IsDirty");
            Assert.AreEqual(viewModelC.OnPropertyIsDirtyChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelCChanges[callIndex++], "DirtyPropertyCount");
            Assert.AreEqual(viewModelCChanges[callIndex++], "IsDirty");
            Assert.AreEqual(viewModelC.OnIsDirtyChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelBChanges[callIndex++], "IsDirtyWithin");
            Assert.AreEqual(viewModelB.OnIsDirtyWithinChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelAChanges[callIndex++], "IsDirtyWithin");
            Assert.AreEqual(viewModelA.OnIsDirtyWithinChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelC.OnPropertyCommittedValueChangedIndex.Value, callIndex++);
            Assert.AreEqual(callIndex, counter.Index);
        }

        private static void DuplicateCommitTest
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelC.Property.Commit();
            Assert.AreEqual(counter.Index, 0);
        }

        private static void AssignCommittedTest
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelC.Property.AssignCommitted("The Committed Value");

            Int32 callIndex = 0;
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "Value");
            Assert.AreEqual(viewModelC.OnPropertyValueChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "CommittedValue");
            Assert.AreEqual(viewModelC.OnPropertyCommittedValueChangedIndex.Value, callIndex++);
            Assert.AreEqual(callIndex, counter.Index);
        }

        private static void DuplicateAssignCommittedTest
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelC.Property.AssignCommitted("The Committed Value");
            Assert.AreEqual(0, counter.Index);
        }

        private static void AssignDefaultValueAsCommittedTest
        (
            ModelForEventSequenceTesting viewModelA,
            Dictionary<Int32, String> viewModelAChanges,
            Dictionary<Int32, String> viewModelAPropertyChanges,
            ModelForEventSequenceTesting viewModelB,
            Dictionary<Int32, String> viewModelBChanges,
            Dictionary<Int32, String> viewModelBPropertyChanges,
            ModelForEventSequenceTesting viewModelC,
            Dictionary<Int32, String> viewModelCChanges,
            Dictionary<Int32, String> viewModelCPropertyChanges,
            CallCounter counter
        )
        {
            viewModelC.Property.AssignCommitted(viewModelC.Property.GetDefaultValue());

            Int32 callIndex = 0;
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "Value");
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "IsDefault");
            Assert.AreEqual(viewModelC.OnPropertyIsDefaultChangedIndex.Value, callIndex++);

            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "ValidationErrors");
            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "IsInvalid");
            Assert.AreEqual(viewModelC.OnPropertyIsInvalidChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelCChanges[callIndex++], "InvalidPropertyCount");
            Assert.AreEqual(viewModelCChanges[callIndex++], "IsInvalid");
            Assert.AreEqual(viewModelC.OnIsInvalidChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelBChanges[callIndex++], "IsInvalidWithin");
            Assert.AreEqual(viewModelB.OnIsInvalidWithinChangedIndex.Value, callIndex++);
            Assert.AreEqual(viewModelAChanges[callIndex++], "IsInvalidWithin");
            Assert.AreEqual(viewModelA.OnIsInvalidWithinChangedIndex.Value, callIndex++);

            Assert.AreEqual(viewModelC.OnPropertyValueChangedIndex.Value, callIndex++);

            Assert.AreEqual(viewModelCPropertyChanges[callIndex++], "CommittedValue");
            Assert.AreEqual(viewModelC.OnPropertyCommittedValueChangedIndex.Value, callIndex++);

            Assert.AreEqual(callIndex, counter.Index);
        }
    }
}
